﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Linq;
using System.Threading;
using System.ComponentModel;
using System.Windows.Browser;

namespace Aspire
{
    public class ContentLoader : INavigationContentLoader
    {
        private Dictionary<PluginPackage, Xap> loadedPackages = new Dictionary<PluginPackage, Xap>();


        public IAsyncResult BeginLoad(Uri targetUri, Uri currentUri, AsyncCallback userCallback, object asyncState)
        {
            XapLoader loader = new XapLoader();
            var result = new ContentLoaderAsyncResult(asyncState, loader);

            PluginPage page = GetFunctionFromUri(targetUri);

            if (loadedPackages.ContainsKey(page.Package))
            {
                FinishLoading(page, result, userCallback);
            }
            else
            {
                int endindex = HtmlPage.Document.DocumentUri.AbsoluteUri.IndexOf('/', 7);
                string serverBaseUrl = HtmlPage.Document.DocumentUri.AbsoluteUri.Substring(0, endindex + 1);

                loader.BeginLoadXap(new Uri(String.Format("{0}ClientBin/{1}", serverBaseUrl, page.Package.Url), UriKind.Absolute), (res) =>
                {
                    try
                    {
                        Xap resultingXap = loader.EndLoadXap(res);
                        loadedPackages[page.Package] = resultingXap;
                        FinishLoading(page, result, userCallback);
                    }
                    catch (Exception e)
                    {
                        //Throw Exception
                    }
                }, null);
            }

            return result;
        }

        private void FinishLoading(PluginPage page, ContentLoaderAsyncResult result, AsyncCallback userCallback)
        {
            object instance = CreatePage(page);
            result.Result = instance;
            userCallback(result);
        }

        private object CreatePage(PluginPage page)
        {
            Xap resultingXap = loadedPackages[page.Package];
            var instance = resultingXap.EntryPointAssembly.CreateInstance(page.ClassName) as Page;
            return instance;
        }

        public bool CanLoad(Uri targetUri, Uri currentUri)
        {
            bool checkResult = false;

            PluginPage page = GetFunctionFromUri(targetUri);

            if (page != null)
            {
                checkResult = true;
                //检查该用户是否有权限访问该功能。
            }

            return checkResult;
        }

        

        public void CancelLoad(IAsyncResult asyncResult)
        {
            return;
        }

        public LoadResult EndLoad(IAsyncResult asyncResult)
        {
            return new LoadResult(((ContentLoaderAsyncResult)asyncResult).Result);
        }

        /// <summary>
        /// 截取URI的URL地址部分，除去参数
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        private string GetUrlFromUri(Uri uri)
        {
            if (!uri.IsAbsoluteUri)
                uri = new Uri(new Uri("dummy:///", UriKind.Absolute), uri.OriginalString);
            return Uri.UnescapeDataString(uri.AbsolutePath.Substring(1));
        }

        /// <summary>
        /// 根据指定的URI获取该URI对应的Function
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        private PluginPage GetFunctionFromUri(Uri uri)
        {
            PluginPage pageInfo = null;

            string url = GetUrlFromUri(uri);

            string[] arrList = url.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            if (arrList.Length > 0)
            {
                List<Function> functions = AspireFramework.Instance.System.Functions;
                for (int i = 0; i < arrList.Length; i++)
                {
                    functions = GetFunctionsByName(functions, arrList[i]);

                    if (functions.Count == 0) 
                        break;

                    if (i != arrList.Length - 1)
                    {
                        List<Function> lst = new List<Function>();
                        foreach (var item in functions)
                        {
                            if (item.Functions != null)
                            {
                                lst.AddRange(item.Functions);
                            }
                        }

                        functions = lst;
                    }
                }

                if (functions.Count > 0)
                {
                    var query = functions.Where(p => p.Page != null).Select(p=>p.Page).Distinct();
#if DEBUG
                    if (query.Count() == 0)
                    {
                        throw new ArgumentException("指定URL未配置错误");
                    }
                    else if (query.Count() > 1)
                    {
                        throw new ArgumentException("指定URL地址配置重复,相同URL地址映射到不同插件上");
                    }
#endif

                    pageInfo = query.FirstOrDefault();
                }
            }

            return pageInfo;
        }


        private List<Function> GetFunctionsByName(List<Function> functions, string path)
        {
            List<Function> lst = new List<Function>();

            foreach (var item in functions)
            {
                if (item.Name == path)
                {
                    lst.Add(item);
                }
            }

            return lst;
        }
    }

    internal class ContentLoaderAsyncResult : IAsyncResult
    {
        public object Result { get; set; }

        public XapLoader Loader { get; set; }

        public ContentLoaderAsyncResult(object asyncState, XapLoader loader)
        {
            this.AsyncState = asyncState;
            this.Loader = loader;
            this.AsyncWaitHandle = new ManualResetEvent(true);
        }

        #region IAsyncResult Members

        public object AsyncState
        {
            get;
            private set;
        }

        public System.Threading.WaitHandle AsyncWaitHandle
        {
            get;
            private set;
        }

        public bool CompletedSynchronously
        {
            get { return true; }
        }

        public bool IsCompleted
        {
            get { return true; }
        }

        #endregion
    }
}
